package com.yuqih.common.web;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.yuqih.common.json.DateJsonDeserializer;

public class WebConfigure implements ApplicationContextAware {

	private ApplicationContext applicationContext;
	
	public void init() throws Exception {
		RequestMappingHandlerAdapter requestMappingHandlerAdapter = applicationContext.getBean(RequestMappingHandlerAdapter.class);
		resetArgumentResolvers(requestMappingHandlerAdapter);
		resetMessageConverters(requestMappingHandlerAdapter);
		requestMappingHandlerAdapter.afterPropertiesSet();
	}
	
	@SuppressWarnings("unchecked")
	private void resetArgumentResolvers(RequestMappingHandlerAdapter requestMappingHandlerAdapter) throws Exception {
		Field field = ReflectionUtils.findField(RequestMappingHandlerAdapter.class, "argumentResolvers");
		field.setAccessible(true);
		HandlerMethodArgumentResolverComposite resolverComposite = (HandlerMethodArgumentResolverComposite) field
				.get(requestMappingHandlerAdapter);

		field = ReflectionUtils.findField(HandlerMethodArgumentResolverComposite.class, "argumentResolvers");
		field.setAccessible(true);
		List<HandlerMethodArgumentResolver> argumentResolvers = (List<HandlerMethodArgumentResolver>) field
				.get(resolverComposite);

		List<HandlerMethodArgumentResolver> changedArgumentResolvers = new ArrayList<HandlerMethodArgumentResolver>();
		for (HandlerMethodArgumentResolver argumentResolver : argumentResolvers) {
			if (argumentResolver instanceof org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor) {
				field = ReflectionUtils.findField(
						org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.class,
						"annotationNotRequired");
				field.setAccessible(true);
				boolean annotationNotRequired = (boolean) field.get(argumentResolver);
				changedArgumentResolvers.add(new ServletModelAttributeMethodProcessor(annotationNotRequired));
			} else {
				changedArgumentResolvers.add(argumentResolver);
			}
		}
		
		argumentResolvers.clear();
		argumentResolvers.addAll(changedArgumentResolvers);
	}
	
	private void resetMessageConverters(RequestMappingHandlerAdapter requestMappingHandlerAdapter) throws Exception {
		List<HttpMessageConverter<?>> messageConverters =  requestMappingHandlerAdapter.getMessageConverters();
		for (HttpMessageConverter<?> converter : messageConverters) {
			if (converter instanceof MappingJackson2HttpMessageConverter) {
				Field field = ReflectionUtils.findField(MappingJackson2HttpMessageConverter.class, "objectMapper");
				field.setAccessible(true);
				ObjectMapper objectMapper = (ObjectMapper)field.get(converter);
				SimpleModule objectIdModule = new SimpleModule();  
				objectIdModule.addDeserializer(Date.class, new DateJsonDeserializer());
				objectMapper.registerModule(objectIdModule);
			}
		}
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

}
